
/**
 * Date:2019年6月13日下午3:43:36
 * Copyright (c) 2019, www.bwbroad.com All Rights Reserved.
 *
*/

package com.xue.im.server.core;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import com.xue.im.common.IMUtil;
import com.xue.im.common.IMUtil.MessageType;
import com.xue.im.common.vo.Message;
import com.xue.im.common.vo.User;
import com.xue.im.server.handler.LoginAuthResponseHandler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.StringUtil;

/**
 * Description: 服务端应用上下文 <br/>
 * Date: 2019年6月13日 下午3:43:36 <br/>
 * 
 * @author xuejianxin
 */
public class IMServerContext {
	// 检查重复登录
	private static final Map<String, Boolean> nodeCheck = new ConcurrentHashMap<>();
	private static final Map<String, User> userMap = new HashMap<>();// 保存用户userid和用户映射
	private static final Map<String, ChannelHandlerContext> userCtxMap = new ConcurrentHashMap<>();
	private static final Map<ChannelHandlerContext, String> ctxUserMap = new ConcurrentHashMap<>();
	static {
		try {
			// 加载用户列表
			Properties p = new Properties();
			p.load(LoginAuthResponseHandler.class.getResourceAsStream("/user.properties"));
			p.forEach((k, v) -> {
				User u = new User();
				String[] uArray = v.toString().split(",");
				u.setUserid((String) k);
				u.setUsername(uArray[0]);
				u.setSex(Integer.parseInt(uArray[1]));
				u.setPassword(uArray[2]);
				u.setIp(uArray[3]);
				System.out.println(u);
				userMap.put(u.getUserid(), u);
			});
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static User getUser(String userid) {
		return userMap.get(userid);
	}

	public static Optional<ChannelHandlerContext> getUserCtx(String userid) {
		return Optional.ofNullable(userCtxMap.get(userid));
	}

	public static String getClientIp(ChannelHandlerContext ctx) {
		// 获取客户端ip
		InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
		String ip = address.getAddress().getHostAddress();
		return ip;
	}

	// 添加到登录节点
	public static void putNode(ChannelHandlerContext ctx) {
		nodeCheck.put(getClientIp(ctx), true);
	}

	// 检查是否重复登录
	public static boolean hasNode(ChannelHandlerContext ctx) {
		// 获取客户端ip
		InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
		String nodeIndex = address.getHostName();
		return nodeCheck.containsKey(nodeIndex);
	}

	// 保存用户上下文
	public static void saveUserCtx(String userid, ChannelHandlerContext ctx) {
		userCtxMap.put(userid, ctx);
		ctxUserMap.put(ctx, userid);
		System.out.printf("[%s] [%s] %s is login\n", IMUtil.getNow(), getClientIp(ctx), userid);
	}

	// 清除用户上下文
	public static void clearUserCtx(ChannelHandlerContext ctx) {
		String userid = ctxUserMap.remove(ctx);
		if (!StringUtil.isNullOrEmpty(userid)) {
			// 移除用户信息
			userCtxMap.remove(userid);
			User u = userMap.get(userid);
			u.setStatus(IMUtil.USER_STATUS_OFFLINE);// 用户下线
			broadcastOnlineMessage(ctx, u);// 广播下线
			System.out.printf("[%s] [%s] %s is logout\n", IMUtil.getNow(), getClientIp(ctx), userid);
		}
	}

	// 获取所有用户列表
	public static List<User> getAllUser() {
		return userMap.values().stream().sorted(new User()).collect(Collectors.toList());
	}

	public static Set<ChannelHandlerContext> getActiveCtx() {
		return ctxUserMap.keySet();
	}

	// 广播用户上线下线信息
	public static void broadcastOnlineMessage(ChannelHandlerContext ctx, User user) {
		// 设置用户上下线信息
		// IMServerContext.getUser(userid).setStatus(status);
		// 构建下线消息
		User u = new User();
		u.setUserid(user.getUserid());
		u.setStatus(user.getStatus());
		u.setIp(user.getIp());
		Message msg = IMUtil.buildMessageObject(MessageType.USER_ONLIE_RESP, u);
		// 广播通知其他用户
		ctx.executor().submit(() -> {
			IMServerContext.getActiveCtx().stream().forEach(c -> c.writeAndFlush(msg));
		});

	}

}
